package com.shenzw.common.sign;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import sun.misc.BASE64Decoder;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.InvalidKeySpecException;

/**
 * @description: 验签切面
 * @author: shenzw
 * @date: 2024/10/26
 */
@Aspect
@Component
@Slf4j
public class VerifySignatureAspect {

    // 公钥字符串
    private static final String PUBLIC_KEY_STR = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDaJzVjC5K6kbS2YE2fiDs6H8pB\n" +
            "JFDGEYqqJJC9I3E0Ebr5FsofdImV5eWdBSeADwcR9ppNbpORdZmcX6SipogKx9PX\n" +
            "5aAO4GPesroVeOs91xrLEGt/arteW8iSD+ZaGDUVV3+wcEdci/eCvFlc5PUuZJou\n" +
            "M2XZaDK4Fg2IRTfDXQIDAQAB";

    @Around("@annotation(verifySignatureAnnotation)")
    public Object verifySignature(ProceedingJoinPoint joinPoint, VerifySignatureAnnotation verifySignatureAnnotation) throws Throwable {
        // 获取方法参数
        Object[] args = joinPoint.getArgs();
        VerificationRequest verificationRequest = JSON.parseObject(JSON.toJSONString(args[0]), VerificationRequest.class);
//        String plain = (String) args[0]; // 原始报文
//        byte[] signature = (byte[]) args[1]; // 签名结果

        String plain = verificationRequest.getData(); // 原始报文
        byte[] signature = verificationRequest.getSignature(); // 签名结果

        // 调用验签方法
        boolean isValid = verify(plain, signature);
        if (!isValid) {
            throw new RuntimeException("验签失败");
        }

        // 继续执行后续逻辑
        return joinPoint.proceed();
    }

    /**
     * 验签方法
     *
     * @param plain         原始报文
     * @param signatureByte 签名结果
     * @return 验签结果
     */
    private static boolean verify(String plain, byte[] signatureByte) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
        // 获取公钥
        PublicKey publicKey = getPublicKey(PUBLIC_KEY_STR);
        // 根据对应算法，获取签名对象实例
        Signature signature = Signature.getInstance("SHA256WithRSA");
        // 初始化签名对象
        signature.initVerify(publicKey);
        // 把原始报文更新到签名对象
        signature.update(plain.getBytes(StandardCharsets.UTF_8));
        // 进行验签
        return signature.verify(signatureByte);
    }

    private static PublicKey getPublicKey(String publicKeyStr) {
        PublicKey publicKey = null;
        try {
            java.security.spec.X509EncodedKeySpec bobPubKeySpec = new java.security.spec.X509EncodedKeySpec(
                    new BASE64Decoder().decodeBuffer(publicKeyStr));
            // RSA对称加密算法
            java.security.KeyFactory keyFactory;
            keyFactory = java.security.KeyFactory.getInstance("RSA");
            // 生成公钥对象
            publicKey = keyFactory.generatePublic(bobPubKeySpec);
        } catch (NoSuchAlgorithmException | IOException e) {
            log.error("生成公钥异常", e);
        } catch (InvalidKeySpecException e) {
            log.error("无效keySpec异常", e);
        }
        return publicKey;
    }
}

